Vault 凭证注入

> 本指南改编自 Vault on MinikubeVault Kubernetes > Sidecar 指南。

大多数 crossplane 提供商至少支持提供以下来源的证书:

  • Kubernetes secret
  • 环境变量
  • 文件系统

提供程序可以选择性地支持其他凭证源,但常用的凭证源涵盖了各种各样的用例。 在使用 Vault 进行secret管理的组织中,有一种特定用例很受欢迎,那就是使用侧卡将凭证注入文件系统。本指南将演示如何使用 Vault Kubernetes Sidecarprovider-gcpprovider-aws 提供凭证。

> 注: 在本指南中,我们将把 GCP 凭据和 AWS 访问密钥 > 复制到 Vault 的 KV secret引擎中。 这是一种使用 Vault > 管理secret的简单通用方法,但不如使用 Vault 的 > AWSAzureGCP 专用云提供商secret引擎那么强大。

设置

> 注意: 本指南将介绍如何设置 Vault 与 > Crossplane 在同一集群中运行。 您也可以选择使用现有的 Vault 实例,该实例在集群外运行,但已启用 Kubernetes 验证。

在开始之前,您必须确保已经安装了 crossplane 和 Vault,并且它们正在集群中运行。

1.安装 crossplane

1kubectl create namespace crossplane-system
2
3helm repo add crossplane-stable https://charts.crossplane.io/stable
4helm repo update
5
6helm install crossplane --namespace crossplane-system crossplane-stable/crossplane

2.安装 Vault Helm 图表

1helm repo add hashicorp https://helm.releases.hashicorp.com
2helm install vault hashicorp/vault

3.解封 Vault 实例

为了让 Vault 从物理存储中访问加密数据,必须对其进行 解封

1kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
2VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
3kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY

4.启用 Kubernetes 验证方法

为了让Vault能够根据Kubernetes服务账户验证请求,必须启用Kubernetes身份验证后端。这需要登录Vault并配置服务账户令牌、API服务器地址和证书。由于我们是在Kubernetes中运行Vault,这些值已经可以通过容器文件系统和环境变量获得。

 1cat cluster-keys.json | jq -r ".root_token" # get root token
 2
 3kubectl exec -it vault-0 -- /bin/sh
 4vault login # use root token from above
 5vault auth enable kubernetes
 6
 7vault write auth/kubernetes/config \
 8        token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
 9        kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
10        kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

5.出口 Vault 集装箱

接下来的步骤将在本地环境中执行。

1exit

创建 GCP 服务账户

为了在 GCP 上配置基础设施,您需要创建一个具有适当权限的服务账户。 在本指南中,我们将只配置一个 CloudSQL 实例,因此服务账户将绑定到 “cloudsql.admin “角色。 以下步骤将设置一个 GCP 服务账户,赋予它必要的权限,以便 crossplane 能够管理 CloudSQL 实例,并在 JSON 文件中发出服务账户凭据。

 1# replace this with your own gcp project id and the name of the service account
 2# that will be created.
 3PROJECT_ID=my-project
 4NEW_SA_NAME=test-service-account-name
 5
 6# create service account
 7SA="${NEW_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
 8gcloud iam service-accounts create $NEW_SA_NAME --project $PROJECT_ID
 9
10# enable cloud API
11SERVICE="sqladmin.googleapis.com"
12gcloud services enable $SERVICE --project $PROJECT_ID
13
14# grant access to cloud API
15ROLE="roles/cloudsql.admin"
16gcloud projects add-iam-policy-binding --role="$ROLE" $PROJECT_ID --member "serviceAccount:$SA"
17
18# create service account keyfile
19gcloud iam service-accounts keys create creds.json --project $PROJECT_ID --iam-account $SA

现在,您应该在 creds.json 中获得有效的服务帐户凭据。

将凭据存储在 Vault 中

设置 Vault 后,您需要在 kv secrets engine 中存储凭证。

> 注意: 以下步骤涉及将凭证复制到容器 > 文件系统,然后再存储到 Vault 中。 您也可以选择将容器端口转发到本地环境 >(kubectl port-forward vault-0 8200:8200),从而使用 Vault 的 > HTTP API 或用户界面。

1.将凭证文件复制到 Vault 容器中

将凭据复制到容器文件系统中,以便存储在 Vault 中。

1kubectl cp creds.json vault-0:/tmp/creds.json

2.启用 KV secret引擎

secret引擎必须启用后才能被引用。 在 secret 路径下启用 kv-v2 secret引擎。

1kubectl exec -it vault-0 -- /bin/sh
2
3vault secrets enable -path=secret kv-v2

3.在 KV 引擎中存储 GCP 凭据

将secret注入到 provider-gcp 控制器 Pod 时,您的 GCP 凭据的路径将被引用。

1vault kv put secret/provider-creds/gcp-default @tmp/creds.json

4.清理证书文件

您不再需要容器文件系统中的 GCP 凭据文件,所以请继续清理它。

1rm tmp/creds.json

创建 AWS IAM 用户

为了在 AWS 上调配基础设施,您需要使用现有的或创建具有适当权限的新 IAM 用户。 以下步骤将创建一个 AWS IAM 用户,并赋予其必要的权限。

> 注意: 如果您已有一个具有适当权限的 IAM 用户,则可以跳过此步骤,但仍需 > Provider ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY 环境变量的值。

 1# create a new IAM user
 2IAM_USER=test-user
 3aws iam create-user --user-name $IAM_USER
 4
 5# grant the IAM user the necessary permissions
 6aws iam attach-user-policy --user-name $IAM_USER --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
 7
 8# create a new IAM access key for the user
 9aws iam create-access-key --user-name $IAM_USER > creds.json
10# assign the access key values to environment variables
11ACCESS_KEY_ID=$(jq -r .AccessKey.AccessKeyId creds.json)
12AWS_SECRET_ACCESS_KEY=$(jq -r .AccessKey.SecretAccessKey creds.json)

将凭据存储在 Vault 中

设置 Vault 后,您需要在 kv secrets engine 中存储凭证。

1.启用 KV secret引擎

secret引擎必须启用后才能被引用。 在 secret 路径下启用 kv-v2 secret引擎。

1kubectl exec -it vault-0 -- env \
2  ACCESS_KEY_ID=${ACCESS_KEY_ID} \
3  AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
4  /bin/sh
5
6vault secrets enable -path=secret kv-v2

2.在 KV 引擎中存储 AWS 凭据

在将secret注入到 provider-aws 控制器 Pod 时,您的 AWS 凭据的路径将被引用。

vault kv put secret/provider-creds/aws-default access_key="$ACCESS_KEY_ID" secret_key="$AWS_SECRET_ACCESS_KEY"

为读取 Provider 凭据创建 Vault 策略

为了让我们的控制器能让 Vault sidecar 将凭证注入其文件系统,您必须将 Podpolicy 关联。该策略将允许在 kv-v2 secrets 引擎中读取和列出 provider-creds 路径上的所有 secrets。

1vault policy write provider-creds - <<EOF
2path "secret/data/provider-creds/*" {
3    capabilities = ["read", "list"]
4}
5EOF

为 Crossplane Provider Pods 创建角色

1.创建角色

最后一步是创建一个与你创建的策略绑定的角色,并将其与一组 Kubernetes 服务账户关联。 该角色可由 crossplane-system 名称空间中的任何 (*) 服务账户承担。

1vault write auth/kubernetes/role/crossplane-providers \
2        bound_service_account_names="*" \
3        bound_service_account_namespaces=crossplane-system \
4        policies=provider-creds \
5        ttl=24h

2.出口 Vault 集装箱

接下来的步骤将在本地环境中执行。

1exit

安装 Provider-gcp

现在您已准备好安装 provider-gcp。 Crossplane 提供了一种 ControllerConfig 类型,允许您自定义提供程序控制器 Pod 的部署。 ControllerConfig 可由任意数量的希望使用其配置的 Provider 对象创建和引用。 在下面的示例中,Pod 注释向 Vault mutating webhook 表示,我们希望将存储在 secret/provider-creds/gcp-default 的secret以 crossplane-providers 角色注入容器文件系统。 此外,还添加了模板格式,以确保secret数据以 provider-gcp 期望的形式呈现。

{% raw %}

 1echo "apiVersion: pkg.crossplane.io/v1alpha1
 2kind: ControllerConfig
 3metadata:
 4  name: vault-config
 5spec:
 6  metadata:
 7    annotations:
 8      vault.hashicorp.com/agent-inject: \"true\"
 9      vault.hashicorp.com/role: "crossplane-providers"
10      vault.hashicorp.com/agent-inject-secret-creds.txt: "secret/provider-creds/gcp-default"
11      vault.hashicorp.com/agent-inject-template-creds.txt: |
12        {{- with secret \"secret/provider-creds/gcp-default\" -}}
13         {{ .Data.data | toJSON }}
14        {{- end -}}
15---
16apiVersion: pkg.crossplane.io/v1
17kind: Provider
18metadata:
19  name: provider-gcp
20spec:
21  package: xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
22  controllerConfigRef:
23    name: vault-config" | kubectl apply -f -

{% endraw %}

配置 Provider-gcp

安装并运行 provider-gcp 后,您需要创建一个 ProviderConfig 来指定文件系统中的凭据,这些凭据应被用于调配引用此 ProviderConfig 的托管资源。 由于此 ProviderConfig 的名称是 default ,它将被任何未明确引用 ProviderConfig 的托管资源所使用。

> 注意: 请确保之前定义的 PROJECT_ID 环境变量 > 设置正确。

 1echo "apiVersion: gcp.crossplane.io/v1beta1
 2kind: ProviderConfig
 3metadata:
 4  name: default
 5spec:
 6  projectID: ${PROJECT_ID}
 7  credentials:
 8    source: Filesystem
 9    fs:
10      path: /vault/secrets/creds.txt" | kubectl apply -f -

要验证 GCP 凭据是否已注入容器,请运行以下命令:

1PROVIDER_CONTROLLER_POD=$(kubectl -n crossplane-system get pod -l pkg.crossplane.io/provider=provider-gcp -o name --no-headers=true)
2kubectl -n crossplane-system exec -it $PROVIDER_CONTROLLER_POD -c provider-gcp -- cat /vault/secrets/creds.txt

提供基础设施

最后一步是实际配置一个 “CloudSQLInstance”。 创建以下对象将在 GCP 上创建一个云 SQL Postgres 数据库。

 1echo "apiVersion: database.gcp.crossplane.io/v1beta1
 2kind: CloudSQLInstance
 3metadata:
 4  name: postgres-vault-demo
 5spec:
 6  forProvider:
 7    databaseVersion: POSTGRES_12
 8    region: us-central1
 9    settings:
10      tier: db-custom-1-3840
11      dataDiskType: PD_SSD
12      dataDiskSizeGb: 10
13  writeConnectionSecretToRef:
14    namespace: crossplane-system
15    name: cloudsqlpostgresql-conn" | kubectl apply -f -

您可以使用以下命令监控数据库配置的进度:

1kubectl get cloudsqlinstance -w

安装 Provider-aws

现在您已准备好安装 provider-aws。 Crossplane 提供了一种 ControllerConfig 类型,允许您自定义提供程序控制器 Pod 的部署。 ControllerConfig 可由任意数量希望使用其配置的 Provider 对象创建和引用。 在下面的示例中, Pod 注解向 Vault mutating webhook 表示,我们希望将存储在 secret/provider-creds/aws-default 中的secret通过担任 crossplane-providers 角色注入容器文件系统。 还添加了一些模板格式,以确保secret数据以 provider-aws 期望的形式呈现。

{% raw %}

 1echo "apiVersion: pkg.crossplane.io/v1alpha1
 2kind: ControllerConfig
 3metadata:
 4  name: aws-vault-config
 5spec:
 6  args:
 7    - --debug
 8  metadata:
 9    annotations:
10      vault.hashicorp.com/agent-inject: \"true\"
11      vault.hashicorp.com/role: \"crossplane-providers\"
12      vault.hashicorp.com/agent-inject-secret-creds.txt: \"secret/provider-creds/aws-default\"
13      vault.hashicorp.com/agent-inject-template-creds.txt: |
14        {{- with secret \"secret/provider-creds/aws-default\" -}}
15          [default]
16          aws_access_key_id="{{ .Data.data.access_key }}"
17          aws_secret_access_key="{{ .Data.data.secret_key }}"
18        {{- end -}}
19---
20apiVersion: pkg.crossplane.io/v1
21kind: Provider
22metadata:
23  name: provider-aws
24spec:
25  package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0
26  controllerConfigRef:
27    name: aws-vault-config" | kubectl apply -f -

{% endraw %}

配置 Provider-aws

安装并运行 “provider-aws “后,您需要创建一个 “ProviderConfig”,指定文件系统中的凭据,用于调配引用该 “ProviderConfig “的托管资源。 由于该 “ProviderConfig “的名称是 “default”,因此将被任何未明确引用 “ProviderConfig “的托管资源所使用。

1echo "apiVersion: aws.crossplane.io/v1beta1
2kind: ProviderConfig
3metadata:
4  name: default
5spec:
6  credentials:
7    source: Filesystem
8    fs:
9      path: /vault/secrets/creds.txt" | kubectl apply -f -

要验证 AWS 凭据是否已注入容器,请运行以下命令:

1PROVIDER_CONTROLLER_POD=$(kubectl -n crossplane-system get pod -l pkg.crossplane.io/provider=provider-aws -o name --no-headers=true)
2kubectl -n crossplane-system exec -it $PROVIDER_CONTROLLER_POD -c provider-aws -- cat /vault/secrets/creds.txt

提供基础设施

最后一步是实际配置一个 “桶”。 创建以下对象将在 AWS 上创建一个 S3 桶。

 1echo "apiVersion: s3.aws.crossplane.io/v1beta1
 2kind: Bucket
 3metadata:
 4  name: s3-vault-demo
 5spec:
 6  forProvider:
 7    acl: private
 8    locationConstraint: us-east-1
 9    publicAccessBlockConfiguration:
10      blockPublicPolicy: true
11    tagging:
12      tagSet:
13        - key: Name
14          value: s3-vault-demo
15  providerConfigRef:
16    name: default" | kubectl apply -f -

您可以使用以下命令监控水桶调配的进度:

1kubectl get bucket -w